package top.jacktgq.cas.aba;
/**
 * 
 * @Title: ABA_AutomicStampedReference.java 
 * @Package top.jacktgq.nolock.aba 
 * @Description: ABA问题：AtomicReference无法感知到其他线程对共享变量值的修改
 * 					1、主线程仅能判断出共享变量的值与最初值A是否相同，不能感知到这种从A改为B，又从B改回A的情况
 * 					2、如果主线程希望：只要有其他线程动过了共享变量，那么自己的cas就算失败，这时，仅比较值是不够的，
 * 					需要再加一个版本号，用到了juc包下的AtomicStampedReference
 * @author CandyWall   
 * @date 2020年11月2日 下午10:01:24 
 * @version V1.0
 */

import java.util.concurrent.atomic.AtomicStampedReference;

import top.jacktgq.utils.LogUtils;
import top.jacktgq.utils.Sleeper;

public class ABA_AutomicStampedReference {
	private static AtomicStampedReference<String> ref = new AtomicStampedReference<String>("A", 0);
	public static void main(String[] args) {
		LogUtils.log("ABA_AutomicStampedReference", "main start...");
		//获取值A
		//这个共享变量被其他线程修改过？
		String prev = ref.getReference();
		int stamp = ref.getStamp();
		LogUtils.log("ABA_AutomicStampedReference", "当前共享变量版本号为：" + stamp);
		other();
		Sleeper.sleep(2);
		//尝试改成C
		LogUtils.log("ABA_AutomicStampedReference", "change A->C " + ref.compareAndSet(prev, "C", stamp, stamp + 1));
	}
	
	private static void other() {
		new Thread(() -> {
			String prev = ref.getReference();
			int stamp = ref.getStamp();
			LogUtils.log("ABA_AutomicStampedReference", "当前共享变量版本号为：" + stamp);
			LogUtils.log("ABA_AutomicStampedReference", "change A->B " + ref.compareAndSet(prev, "C", stamp, stamp + 1));
		}, "t1").start();;
		Sleeper.sleep(1);
		new Thread(() -> {
			String prev = ref.getReference();
			int stamp = ref.getStamp();
			LogUtils.log("ABA_AutomicStampedReference", "当前共享变量版本号为：" + stamp);
			LogUtils.log("ABA_AutomicStampedReference", "change B->A " + ref.compareAndSet(prev, "C", stamp, stamp + 1));
		}, "t2").start();
	}
}
